#ifndef RS274NGC_INTERP_H
#define RS274NGC_INTERP_H
#include "rs274ngc.hh"
#include "interp_internal.hh"
#include "../hiredis/redis.hh"
#include "config.h"
#include <vector>
#include <utility>
#include <stack>
#include "rcs.hh"           // NML classes, nmlErrorFormat()
#include "nml_intf/zuc.hh"  // ZUC NML
#include "nml_intf/zuc_nml.hh"
#include "nml_oi.hh"

typedef enum
{
    EOC_CR,
    EOC_LF,
    EOC_CRLF,
    EOC_LFCR,
    EOC_NONE
} EocType;

/**
	* @param speed_override_symbol judge dynamic speed disable or enable,1 is enable,0 is disable
    * @param move_type move type select,MOV_L is movl,MOV_J is movj
    * @param vel  velocity value
	* @param acc  acceleration value
	*/
typedef struct
{
    int speed_override_symbol;
    double vel;
    double acc;
    double ori_vel;
    double ori_acc;
} SpeedOverrideInfo;

class VsnComm
{
public:
    VsnComm() : initialized(false), hasConnResp(false), eocType(EOC_NONE)
    {
        postOpenCmd.clear();
        preTrigCmd.clear();
        trigCmd.clear();
        postTrigCmd.clear();
        preLocCmd.clear();
        locCmd.clear();
        postLocCmd.clear();
    }

    void reset()
    {
        initialized = false;
        hasConnResp = false;
        eocType = EOC_NONE;
        postOpenCmd.clear();
        preTrigCmd.clear();
        trigCmd.clear();
        postTrigCmd.clear();
        preLocCmd.clear();
        locCmd.clear();
        postLocCmd.clear();
    }

public:
    bool initialized;  ///< initialized or not
    bool hasConnResp;  ///< has response or not when connecting server
    EocType eocType;
    std::vector<std::string> postOpenCmd;

    std::vector<std::string> preTrigCmd;
    std::vector<std::string> trigCmd;
    std::vector<std::string> postTrigCmd;

    std::vector<std::string> preLocCmd;
    std::vector<std::string> locCmd;
    std::vector<std::string> postLocCmd;
};

struct Var
{
    std::string varName;
    jaka_value varVal;
};

class Interp : public InterpBase
{
public:
    Interp(int threadId = 0);
    ~Interp();

    /* Interface functions to call to tell the interpreter what to do.
    Return values indicate status of execution.
    These functions may change the state of the interpreter. */

    // close the currently open NC code file
    int close();

    void clear_crossfile_environment(setup& _setup);

    // execute a line of NC code
    int execute(const char* command);
    int execute();

    int execute(const char* command, int line_no);  //used for MDI calls to specify the pseudo MDI line number

    // stop running
    int exit();

    // get ready to run
    int init();

    // load a tool table
    int load_tool_table();

    // open a file of NC code
    int open(const char* filename);

    // read the mdi or the next line of the open NC code file
    int read(const char* mdi);
    int read();
    int read(double* para, int id);

    // reset yourself
    int reset();

    // restore interpreter variables from a file
    int restore_parameters(const char* filename);

    // save interpreter variables to file
    int save_parameters(const char* filename, const double parameters[], int force);

    // restore user defined interpreter variables from a file
    int restore_user_parameters();

    // save user defined interpreter variables from a file
    int save_user_parameters(int force);

    // synchronize your internal model with the external world
    int synch();

    /* Interface functions to call to get information from the interpreter.
    If a function has a return value, the return value contains the information.
    If a function returns nothing, information is copied into one of the
    arguments to the function. These functions do not change the state of
    the interpreter. */

    // copy active G codes into array [0]..[15]
    void active_g_codes(int* codes);

    // copy active M codes into array [0]..[9]
    void active_m_codes(int* codes);

    // copy active F, S settings into array [0]..[2]
    void active_settings(double* settings);

    // copy the text of the error message whose number is error_code into the
    // error_text array, but stop at max_size if the text is longer.
    char* error_text(int error_code, int* suberrcode, char* error_text, size_t max_size);

    void setError(int error_code, const char* fmt, ...) __attribute__((format(printf, 3, 4)));

    // copy the name of the currently open file into the file_name array,
    // but stop at max_size if the name is longer
    char* file_name(char* file_name, size_t max_size);

    // return the length of the most recently read line
    size_t line_length();

    // copy the text of the most recently read line into the line_text array,
    // but stop at max_size if the text is longer
    char* line_text(char* line_text, size_t max_size);

    int current_line();
    // return the current sequence number (how many lines read)
    int sequence_number();

    // copy the function name from the stack_index'th position of the
    // function call stack at the time of the most recent error into
    // the function name string, but stop at max_size if the name is longer
    char* stack_name(int stack_index, char* function_name, size_t max_size);

    // Get the parameter file name from the ini file.
    int ini_load(const char* filename);

    int line() { return sequence_number(); }

    int call_level();

    char* command(char* buf, size_t len)
    {
        line_text(buf, len);
        return buf;
    }

    char* file(char* buf, size_t len)
    {
        file_name(buf, len);
        return buf;
    }

    int get_callstack(int i, char* buf, int* line);

    int init_tool_parameters();
    int default_tool_parameters();
    int on_abort(int reason, const char* message);

    void set_loglevel(int level);
    void store_variables(const std::string& varName, const jaka_value& value);
    // for now, public - for boost.python access
    int find_named_param(const char* nameBuf, int* status, jaka_value* value);
    int store_named_param(setup_pointer settings, const char* nameBuf, jaka_value value, int override_readonly = 0);

    int add_named_param(const char* nameBuf, int attr = 0);
    int fetch_ini_param(const char* nameBuf, int* status, jaka_value* value);
    int fetch_hal_param(const char* nameBuf, int* status, jaka_value* value);

    // common combination of add_named_param and store_named_param
    // int assign_named_param(const char *nameBuf, int attr = 0, double value = 0.0);
    remap_pointer remapping(const char* code);
    remap_pointer remapping(const char letter, int number = -1);
    int find_tool_pocket(setup_pointer settings, int toolno, int* pocket);

    // private:
    //protected:  // for boost wrapper access

    /* Function prototypes for all  functions */

    int arc_data_comp_ijk(int move,
                          int plane,
                          int side,
                          double tool_radius,
                          double current_x,
                          double current_y,
                          double end_x,
                          double end_y,
                          int ij_absolute,
                          double i_number,
                          double j_number,
                          int p_number,
                          double* center_x,
                          double* center_y,
                          int* turn,
                          double radius_tolerance,
                          double spiral_abs_tolerance,
                          double spiral_rel_tolerance);

    int arc_data_comp_r(int move,
                        int plane,
                        int side,
                        double tool_radius,
                        double current_x,
                        double current_y,
                        double end_x,
                        double end_y,
                        double big_radius,
                        int p_number,
                        double* center_x,
                        double* center_y,
                        int* turn,
                        double radius_tolerance);

    int arc_data_ijk(int move,
                     int plane,
                     double current_x,
                     double current_y,
                     double end_x,
                     double end_y,
                     int ij_absolute,
                     double i_number,
                     double j_number,
                     int p_number,
                     double* center_x,
                     double* center_y,
                     int* turn,
                     double radius_tolerance,
                     double spiral_abs_tolerance,
                     double spiral_rel_tolerance);

    int arc_data_r(int move,
                   int plane,
                   double current_x,
                   double current_y,
                   double end_x,
                   double end_y,
                   double radius,
                   int p_number,
                   double* center_x,
                   double* center_y,
                   int* turn,
                   double radius_tolerance);
    int check_g_codes(block_pointer block, setup_pointer settings);
    int check_items(block_pointer block, setup_pointer settings);
    int check_m_codes(block_pointer block);
    int check_other_codes(block_pointer block);
    int close_and_downcase(char* line);
    int convert_nurbs(int move, block_pointer block, setup_pointer settings);
    int convert_spline(int move, block_pointer block, setup_pointer settings);
    int comp_get_current(setup_pointer settings, double* x, double* y, double* z);
    int comp_set_current(setup_pointer settings, double x, double y, double z);
    int comp_get_programmed(setup_pointer settings, double* x, double* y, double* z);
    int comp_set_programmed(setup_pointer settings, double x, double y, double z);
    int convert_arc(int move, block_pointer block, setup_pointer settings);
    int convert_arc2(int move,
                     block_pointer block,
                     setup_pointer settings,
                     double* current1,
                     double* current2,
                     double* current3,
                     double end1,
                     double end2,
                     double end3,
                     double AA_end,
                     double BB_end,
                     double CC_end,
                     double u_end,
                     double v_end,
                     double w_end,
                     double offset1,
                     double offset2);

    int convert_arc_comp1(int move,
                          block_pointer block,
                          setup_pointer settings,
                          double end_x,
                          double end_y,
                          double end_z,
                          double offset_x,
                          double offset_y,
                          double AA_end,
                          double BB_end,
                          double CC_end,
                          double u_end,
                          double v_end,
                          double w_end);

    int convert_arc_comp2(int move,
                          block_pointer block,
                          setup_pointer settings,
                          double end_x,
                          double end_y,
                          double end_z,
                          double offset_x,
                          double offset_y,
                          double AA_end,
                          double BB_end,
                          double CC_end,
                          double u_end,
                          double v_end,
                          double w_end);
    char arc_axis1(int plane);
    char arc_axis2(int plane);
    int convert_axis_offsets(int g_code, block_pointer block, setup_pointer settings);
    int convert_param_comment(char* comment, char* expanded, int len);
    int convert_comment(char* comment, bool enqueue = true);
    int convert_control_mode(int g_code, double tolerance, double naivecam_tolerance, setup_pointer settings);
    int convert_adaptive_mode(int g_code, setup_pointer settings);

    int convert_coordinate_system(int g_code, setup_pointer settings);
    int convert_cutter_compensation(int g_code, block_pointer block, setup_pointer settings);
    int convert_cutter_compensation_off(setup_pointer settings);
    int convert_cutter_compensation_on(int side, block_pointer block, setup_pointer settings);
    int convert_cycle(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_g81(block_pointer block, CANON_PLANE plane, double x, double y, double clear_z, double bottom_z);
    int convert_cycle_g82(block_pointer block, CANON_PLANE plane, double x, double y, double clear_z, double bottom_z, double dwell);
    int convert_cycle_g73(block_pointer block, CANON_PLANE plane, double x, double y, double r, double clear_z, double bottom_z, double delta);
    int convert_cycle_g83(block_pointer block, CANON_PLANE plane, double x, double y, double r, double clear_z, double bottom_z, double delta);
    int convert_cycle_g74_g84(block_pointer block,
                              CANON_PLANE plane,
                              double x,
                              double y,
                              double clear_z,
                              double bottom_z,
                              CANON_DIRECTION direction,
                              CANON_SPEED_FEED_MODE mode,
                              int motion,
                              double dwell);
    int convert_cycle_g85(block_pointer block, CANON_PLANE plane, double x, double y, double r, double clear_z, double bottom_z);
    int convert_cycle_g86(block_pointer block, CANON_PLANE plane, double x, double y, double clear_z, double bottom_z, double dwell, CANON_DIRECTION direction);
    int convert_cycle_g87(block_pointer block,
                          CANON_PLANE plane,
                          double x,
                          double offset_x,
                          double y,
                          double offset_y,
                          double r,
                          double clear_z,
                          double middle_z,
                          double bottom_z,
                          CANON_DIRECTION direction);
    int convert_cycle_g88(block_pointer block, CANON_PLANE plane, double x, double y, double bottom_z, double dwell, CANON_DIRECTION direction);
    int convert_cycle_g89(block_pointer block, CANON_PLANE plane, double x, double y, double clear_z, double bottom_z, double dwell);
    int convert_cycle_xy(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_yz(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_zx(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_uv(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_vw(int motion, block_pointer block, setup_pointer settings);
    int convert_cycle_wu(int motion, block_pointer block, setup_pointer settings);
    int convert_distance_mode(int g_code, setup_pointer settings);
    int convert_ijk_distance_mode(int g_code, setup_pointer settings);
    int convert_lathe_diameter_mode(int g_code, block_pointer block, setup_pointer settings);
    int convert_dwell(int line_num, setup_pointer settings, double time, short sub_thread);
    int convert_feed_mode(int g_code, setup_pointer settings);
    int convert_feed_rate(block_pointer block, setup_pointer settings);
    int convert_g(block_pointer block, setup_pointer settings);
    int convert_home(int move, block_pointer block, setup_pointer settings);
    int convert_savehome(int move, block_pointer block, setup_pointer settings);
    int convert_length_units(int g_code, setup_pointer settings);
    int convert_m(block_pointer block, setup_pointer settings);
    int convert_modal_0(int code, block_pointer block, setup_pointer settings);
    int convert_motion(int motion, block_pointer block, setup_pointer settings);
    int convert_retract_mode(int g_code, setup_pointer settings);
    int convert_setup(block_pointer block, setup_pointer settings);
    int convert_setup_tool(block_pointer block, setup_pointer settings);
    int convert_set_plane(int g_code, setup_pointer settings);
    int convert_speed(block_pointer block, setup_pointer settings);
    int convert_stop(block_pointer block, setup_pointer settings);
    int convert_straight(int move, block_pointer block, setup_pointer settings);
    /*added by zxqi, to support movl and movj*/
    int convert_movl(int move, block_pointer block, setup_pointer settings);
    int convert_movj(int move, block_pointer block, setup_pointer settings);
    int convert_movc(int move, block_pointer block, setup_pointer settings);

    int convert_movs(int move, block_pointer block, setup_pointer settings);
    int convert_pause(block_pointer block, setup_pointer settings);
    int convert_resume(block_pointer block, setup_pointer settings);
    int convert_exit(block_pointer block, setup_pointer settings);
    int convert_tio_update_signal(block_pointer block, setup_pointer settings);
    int convert_tio_send_command(block_pointer block, setup_pointer settings);

    int convert_straight_comp1(int move,
                               block_pointer block,
                               setup_pointer settings,
                               double px,
                               double py,
                               double end_z,
                               double AA_end,
                               double BB_end,
                               double CC_end,
                               double u_end,
                               double v_end,
                               double w_end);
    int convert_straight_comp2(int move,
                               block_pointer block,
                               setup_pointer settings,
                               double px,
                               double py,
                               double end_z,
                               double AA_end,
                               double BB_end,
                               double CC_end,
                               double u_end,
                               double v_end,
                               double w_end);
    int convert_threading_cycle(block_pointer block, setup_pointer settings, double end_x, double end_y, double end_z);
    int convert_tool_change(setup_pointer settings);
    int convert_tool_length_offset(int g_code, block_pointer block, setup_pointer settings);
    int convert_tool_select(block_pointer block, setup_pointer settings);
    int convert_set_tool(int line_num, double* tool_offset, setup_pointer setttings);
    int convert_set_tool_id(int line_num, int tool_id, setup_pointer settings);
    int convert_set_user_frame(ZucPose* user_offset, setup_pointer settings);
    int convert_set_userframe(int line_num, double* user_frame, setup_pointer setttings);
    int convert_set_user_id(int line_num, int user_id, setup_pointer settings);

    int convert_set_payload(int line_num, Payload payload, setup_pointer settings);
    int convert_set_clsn_level(int line_num, int clsn_level, setup_pointer settings);

    int convert_set_admit_ctrl_config(int line_num, int axis, FtConfig ftConfig, int now, setup_pointer settings);
    int convert_set_end_force_condition(int line_num, int axis, EndForceCond endForceCond, setup_pointer settings);
    int convert_compliantcondition(int line_num, double* compliantCondition, setup_pointer settings);
    int convert_set_compliant_type(int line_num, int* typeEna, setup_pointer settings);
    int convert_velCompliantlevel(int line_num, double* velCompliantCtrl, setup_pointer settings);
    int convert_set_force_control_frame(int line_num, int ftFrame, setup_pointer settings);
    int convert_disable_force_control(int line_num, setup_pointer settings, int disableForceCtrl);
    int convert_admit_enable(int enable, setup_pointer settings);
    int convert_conveyor_linear_enable(double x, double y, double z, double unit, double max_dis, setup_pointer settings);
    int convert_conveyor_circular_enable(double p1x,
                                         double p1y,
                                         double p1z,
                                         double p2x,
                                         double p2y,
                                         double p2z,
                                         double p3x,
                                         double p3y,
                                         double p3z,
                                         double unit,
                                         int rotate_tool,
                                         double max_dis,
                                         setup_pointer settings);
    int convert_conveyor_disable();

    int cycle_feed(block_pointer block, CANON_PLANE plane, double end1, double end2, double end3);
    int cycle_traverse(block_pointer block, CANON_PLANE plane, double end1, double end2, double end3);
    int enhance_block(block_pointer block, setup_pointer settings);
    int _execute(const char* command = 0);
    int execute_binary(double* left, int operation, double* right);
    int execute_binary1(double* left, int operation, double* right);
    int execute_binary2(double* left, int operation, double* right);
    int execute_binary(jaka_value& left, int operation, jaka_value& right);
    int execute_binary1(jaka_value& left, int operation, jaka_value& right);
    int execute_binary2(jaka_value& left, int operation, jaka_value& right);

    int execute_block(block_pointer block, setup_pointer settings);
    int execute_unary(double* double_ptr, int operation);
    double find_arc_length(double x1, double y1, double z1, double center_x, double center_y, int turn, double x2, double y2, double z2);
    int find_current_in_system(setup_pointer s, int system, double* x, double* y, double* z, double* a, double* b, double* c, double* u, double* v, double* w);
    int find_current_in_system_without_tlo(setup_pointer s,
                                           int system,
                                           double* x,
                                           double* y,
                                           double* z,
                                           double* a,
                                           double* b,
                                           double* c,
                                           double* u,
                                           double* v,
                                           double* w);
    int find_ends(block_pointer block,
                  setup_pointer settings,
                  double* px,
                  double* py,
                  double* pz,
                  double* AA_p,
                  double* BB_p,
                  double* CC_p,
                  double* u_p,
                  double* v_p,
                  double* w_p);
    int find_ends_joint(block_pointer block,
                        setup_pointer settings,
                        double* px,
                        double* py,
                        double* pz,
                        double* AA_p,
                        double* BB_p,
                        double* CC_p,
                        double* u_p,
                        double* v_p,
                        double* w_p,
                        double* corr_joints);
    int find_relative(double x1,
                      double y1,
                      double z1,
                      double AA_1,
                      double BB_1,
                      double CC_1,
                      double u_1,
                      double v_1,
                      double w_1,
                      double* x2,
                      double* y2,
                      double* z2,
                      double* AA_2,
                      double* BB_2,
                      double* CC_2,
                      double* u_2,
                      double* v_2,
                      double* w_2,
                      setup_pointer settings);
    double find_straight_length(double x2,
                                double y2,
                                double z2,
                                double AA_2,
                                double BB_2,
                                double CC_2,
                                double u_w,
                                double v_2,
                                double w_2,
                                double x1,
                                double y1,
                                double z1,
                                double AA_1,
                                double BB_1,
                                double CC_1,
                                double u_1,
                                double v_1,
                                double w_1);
    double find_turn(double x1, double y1, double center_x, double center_y, int turn, double x2, double y2);
    int init_block(block_pointer block);
    int inverse_time_rate_arc(double x1,
                              double y1,
                              double z1,
                              double cx,
                              double cy,
                              int turn,
                              double x2,
                              double y2,
                              double z2,
                              block_pointer block,
                              setup_pointer settings);
    int inverse_time_rate_straight(double end_x,
                                   double end_y,
                                   double end_z,
                                   double AA_end,
                                   double BB_end,
                                   double CC_end,
                                   double u_end,
                                   double v_end,
                                   double w_end,
                                   block_pointer block,
                                   setup_pointer settings);
    int move_endpoint_and_flush(setup_pointer, double, double);
    int parse_line(char* line, block_pointer block, setup_pointer settings);
    int precedence(int an_operator);
    int _read(const char* command);
    int read_a(char* line, int* counter, block_pointer block, double* parameters);
    int read_atan2(char* line, int* counter, double* double_ptr, double* parameters);
    int read_atsign(char* line, int* counter, block_pointer block, double* parameters);
    int read_b(char* line, int* counter, block_pointer block, double* parameters);
    int read_c(char* line, int* counter, block_pointer block, double* parameters);
    int read_carat(char* line, int* counter, block_pointer block, double* parameters);
    int read_comment(char* line, int* counter, block_pointer block, double* parameters);
    int read_semicolon(char* line, int* counter, block_pointer block, double* parameters);
    int read_d(char* line, int* counter, block_pointer block, double* parameters);
    int read_e(char* line, int* counter, block_pointer block, double* parameters);
    int read_f(char* line, int* counter, block_pointer block, double* parameters);
    int read_g(char* line, int* counter, block_pointer block, double* parameters);

    int read_movj(char* line, int* counter, block_pointer block, double* parameters);
    int read_movl(char* line, int* counter, block_pointer block, double* parameters);
    int read_movc(char* line, int* counter, block_pointer block, double* parameters);
    int read_movs(char* line, int* counter, block_pointer block, double* parameters);
    int read_execute_script(char* line, int* counter, block_pointer block, setup_pointer settings);
    int scripts_syncy_parse_execute(char* line, int* counter, block_pointer block, setup_pointer settings);
    std::string read_execute_script_path(char* line);  //read  file path
    int read_sleep(char* line, int* counter, block_pointer block, double* parameters);

    int read_admitenable(char* line, int* counter, block_pointer block, double* parameters);

    int read_setdout(char* line, int* counter, block_pointer block, double* parameters);
    int read_setaout(char* line, int* counter, block_pointer block, double* parameters);
    int read_getdout(char* line, int* counter, double* double_ptr, double* parameters);
    int read_getaout(char* line, int* counter, double* double_ptr, double* parameters);
    int read_getdin(char* line, int* counter, double* double_ptr, double* parameters);
    int read_getain(char* line, int* counter, double* double_ptr, double* parameters);
    int read_getatljointpose(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getatltcppose(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getatlflangepose(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_gettooloffsetsof(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_gettooloffsets(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getuseroffsetsof(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getuseroffsets(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getclsnsensitivity(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getpayload(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getsensortorque(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    int read_waitinput(char* line, int* counter, block_pointer block, double* parameters);
    int read_gettimeout(char* line, int* counter, double* double_ptr, double* parameters);
    // int read_setarrayelement(char *line, int *counter, double *parameters);
    // int read_getarrayelement(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getlength(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    int read_poseadd(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_posesub(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_poseinv(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_posedist(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_posetrans(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_poseintpl(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_xyplanetrans(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_yzplanetrans(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_zxplanetrans(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    int read_kinInverse(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_kinForward(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_isPoseReachable(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    /*speed override operator */
    int read_override_speed_par(char* line, int* counter);
    int read_stop_override_speed(char* line, int* counter);

    /*set planner type */
    int read_set_planner_type(char* line, int* counter);
    int read_close_speed_planner(char* line, int* counter);

    int read_socketopen(char* line, int* counter, int* int_ptr, double* parameters);
    int read_socketclose(char* line, int* counter, double* parameters);
    int read_socketrecv(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_socketgetvar(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_socketreadreal(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_socketreadstring(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_socketsend(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_socketsendbyte(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_stringconcat(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_strcmp(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    int read_sprintf(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int do_sscanf(const char* buf, const char* s, double* parameters, std::vector<std::string> ap);
    int read_sscanf(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getstringfromarray(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_getarrayfromstring(char* line, int* counter, jaka_value* value_ptr, double* parameters);

    int read_settool(char* line, int* counter, block_pointer block, double* parameters);
    int read_settoolid(char* line, int* counter, block_pointer block, double* parameters);
    int read_setuserframe(char* line, int* counter, block_pointer block, double* parameters);
    int read_setuserid(char* line, int* counter, block_pointer block, double* parameters);
    int read_setpayload(char* line, int* counter, block_pointer block, double* parameters);
    int read_setadmitctrlconfig(char* line, int* counter, block_pointer block, double* parameters);
    int read_setendforcecondition(char* line, int* counter, block_pointer block, double* parameters);
    int read_setcompliantctrlcondition(char* line, int* counter, block_pointer block, double* parameters);
    int read_setcomplianttype(char* line, int* counter, block_pointer block, double* parameters);
    int read_setvelcompliantlevel(char* line, int* counter, block_pointer block, double* parameters);
    int read_setforcectrlframe(char* line, int* counter, block_pointer block, double* parameters);
    int read_disableforcecontrol(char* line, int* counter, block_pointer block, double* parameters);
    int read_setcollisionlevel(char* line, int* counter, block_pointer block, double* parameters);
    int read_logmsg(char* line, int* counter, block_pointer block, double* parameters);
    int read_getsysclock(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_pause(char* line, int* counter, block_pointer block, double* parameters);
    int read_resume(char* line, int* counter, block_pointer block, double* parameters);
    int read_exit(char* line, int* counter, block_pointer block, double* parameters);
    int read_tioupdatesignal(char* line, int* counter, block_pointer block, double* parameters);
    int read_tiosendcommand(char* line, int* counter, block_pointer block, double* parameters);
    int read_tiogetsignalvalue(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_threadcreate(char* line, int* counter, block_pointer block, double* parameters);
    int read_threaddestroy(char* line, int* counter, block_pointer block, double* parameters);
    int read_threadjoin(char* line, int* counter, block_pointer block, double* parameters);
    int read_threadentermutex(char* line, int* counter, block_pointer block, double* parameters);
    int read_threadexitmutex(char* line, int* counter, block_pointer block, double* parameters);

    int read_h(char* line, int* counter, block_pointer block, double* parameters);
    int read_i(char* line, int* counter, block_pointer block, double* parameters);
    int read_integer_unsigned(char* line, int* counter, int* integer_ptr);
    int read_integer_value(char* line, int* counter, int* integer_ptr, double* parameters);
    int read_items(block_pointer block, char* line, double* parameters, setup_pointer settings);
    int read_j(char* line, int* counter, block_pointer block, double* parameters);
    int read_k(char* line, int* counter, block_pointer block, double* parameters);
    int read_l(char* line, int* counter, block_pointer block, double* parameters);
    int read_n_number(char* line, int* counter, block_pointer block);
    int read_m(char* line, int* counter, block_pointer block, double* parameters);
    int read_o(char* line, int* counter, block_pointer block, double* parameters);

    int read_one_item(char* line, int* counter, block_pointer block, double* parameters);
    int read_operation(char* line, int* counter, int* operation);
    int read_operation_unary(char* line, int* counter, int* operation);
    int read_p(char* line, int* counter, block_pointer block, double* parameters);

    int lookup_named_param(const char* nameBuf, double index, jaka_value* value);
    int init_readonly_param(const char* nameBuf, jaka_value value, int attr);
    int free_named_parameters(context_pointer frame);
    int save_settings(setup_pointer settings);
    int restore_settings(setup_pointer settings, int from_level);
    int gen_settings(double* current, double* saved, std::string& cmd);
    int gen_g_codes(int* current, int* saved, std::string& cmd);
    int gen_m_codes(int* current, int* saved, std::string& cmd);
    int read_name(char* line, int* counter, char* nameBuf);
    int read_named_parameter(char* line, int* counter, char* paramNameBuf, jaka_value* value_ptr, double* parameters, bool check_exists);
    int read_parameter(char* line, int* counter, jaka_value* value_ptr, double* parameters, bool check_exists);
    int read_parameter_setting(char* line, int* counter, block_pointer block, double* parameters);
    int read_bracketed_parameter(char* line, int* counter, jaka_value* value_ptr, double* parameters, bool check_exists);
    int read_named_parameter_setting(char* line, int* counter, char** param, double* parameters);
    int read_q(char* line, int* counter, block_pointer block, double* parameters);
    int read_r(char* line, int* counter, block_pointer block, double* parameters);
    int read_real_expression(char* line, int* counter, double* hold2, double* parameters);
    int read_real_number(char* line, int* counter, double* double_ptr);
    int read_real_value(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_array_value(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_string_value(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_s(char* line, int* counter, block_pointer block, double* parameters);
    int read_t(char* line, int* counter, block_pointer block, double* parameters);
    int read_text(const char* command, FILE* inport, char* raw_line, char* line, int* length);
    int read_unary(char* line, int* counter, jaka_value* value_ptr, double* parameters);
    int read_u(char* line, int* counter, block_pointer block, double* parameters);
    int read_v(char* line, int* counter, block_pointer block, double* parameters);
    int read_w(char* line, int* counter, block_pointer block, double* parameters);
    int read_x(char* line, int* counter, block_pointer block, double* parameters);
    int read_y(char* line, int* counter, block_pointer block, double* parameters);
    int read_z(char* line, int* counter, block_pointer block, double* parameters);
    int refresh_actual_position(setup_pointer settings);
    int write_g_codes(block_pointer block, setup_pointer settings);
    int write_m_codes(block_pointer block, setup_pointer settings);
    int write_settings(setup_pointer settings);
    int unwrap_rotary(double*, double, double, double, char);
    bool isreadonly(int index);

    int read_convey_linear_enable(char* line, int* counter, block_pointer block, double* parameters);
    int read_convey_circular_enable(char* line, int* counter, block_pointer block, double* parameters);
    int read_convey_disable(char* line, int* counter, block_pointer block, double* parameters);

    // O_word stuff

    int findFile(                // ARGUMENTS
        char* direct,            // the directory to start looking in
        char* target,            // the name of the file to find
        char* foundFileDirect);  // where to store the result

    int control_save_offset(/* ARGUMENTS                   */
                            // int line,                  /* (o-word) line number        */
                            block_pointer block,     /* pointer to a block of RS274/NGC instructions */
                            setup_pointer settings); /* pointer to machine settings */

    int control_find_oword(                        /* ARGUMENTS, any one of the block        */
                           block_pointer block,    /* block pointer to get (o-word) name        */
                           setup_pointer settings, /* pointer to machine settings */
                           offset_pointer* ppo);
    //  int *o_index);             /* the index of o-word (returned) */

    int control_back_to(                         /* ARGUMENTS                   */
                        block_pointer block,     // pointer to block
                        setup_pointer settings); /* pointer to machine settings */

    // jump between if cases
    int control_jump_to(block_pointer block, setup_pointer settings, offset_pointer op);

    // find specified oword of if/while/repeat sentense
    int control_find_curroword(block_pointer block, setup_pointer settings, offset_pointer* ppo);
    // find if oword of if sentense
    int control_find_ifhead(block_pointer block, setup_pointer settings, offset_pointer* ppo);
    // find the next case of if sentense
    int control_find_ifnext(block_pointer block, setup_pointer settings, offset_pointer* ppo);
    // find the endif case of if sentense
    int control_find_ifend(block_pointer block, setup_pointer settings, offset_pointer* ppo);
    // find the end of while sentense
    int control_find_whileend(block_pointer block, setup_pointer settings, offset_pointer* ppo);

    // establish a new subroutine context
    int enter_context(setup_pointer settings, block_pointer block);
    // leave current subroutine context
    int leave_context(setup_pointer settings, bool restore = true);

    //int call_fsm(setup_pointer settings, int event);
    //int execute_pycall(setup_pointer settings, const char *name, int call_phase);
    int execute_call(setup_pointer settings, context_pointer current_frame, int call_type);
    int execute_return(setup_pointer settings, context_pointer current_frame, int call_type);
    //int execute_remap(setup_pointer settings, int call_phase);   // remap call state machine
    int handler_returned(setup_pointer settings, context_pointer active_frame, const char* name, bool osub);
    int read_inputs(setup_pointer settings);

    int convert_control_functions(                         /* ARGUMENTS           */
                                  block_pointer block,     /* pointer to a block of RS274/NGC instructions */
                                  setup_pointer settings); /* pointer to machine settings */

    // parse a REMAP= descriptor from the ini file
    int parse_remap(const char* inistring, int lineno);

    // step through parsed block and collect remapped items in
    // block.remappings set
    int find_remappings(block_pointer block, setup_pointer settings);

    // establish a new remapping context
    int enter_remap(void);
    // leave current remapping context
    int leave_remap(void);

    // callback when remapping handler done
    int remap_finished(int status);

    int report_error(setup_pointer settings, int status, const char* text);

    //  add named params/param dict if argspec given
    // present optional words to the subroutine's local variables and Py dict
    int add_parameters(setup_pointer settings, block_pointer cblock, char* posarglist);

    int init_named_parameters();
    int init_python_predef_parameter(const char* name);

    int parse_remote_var_set(Var& var);

    bool has_user_mcode(setup_pointer settings, block_pointer block);

    int set_prog_start_line(int start_line);

    int update_start_line(setup_pointer settings);

    int set_parsing_flag(bool flag);

    int set_endforcecond_flag(int flag_value);

    int set_user_defined_var(int id, double value);

    int skip_nested_code(int& skipCodeLevel, setup& settings);

#define M_BUILTIN(m) (_ems[m] != -1)
#define G_BUILTIN(g) (_gees[g] != -1)

    // range for user-remapped M-codes
    // and M6,M61
    // this is overdue for a bitset
#define M_REMAPPABLE(m)                                                                                                                                 \
    (((m > 199) && (m < 1000)) || ((m > 0) && (m < 100) && !M_BUILTIN(m)) || (m == 6) || (m == 61) || (m == 0) || (m == 1) || (m == 60) || (m == 62) || \
     (m == 63) || (m == 64) || (m == 65) || (m == 66) || (m == 67) || (m == 68))

    // range for user-remapped G-codes
#define G_REMAPPABLE(g) ((g > 0) && (g < 1000) && !G_BUILTIN(g))

#define IS_USER_GCODE(x) (G_REMAPPABLE(x) && _setup.g_remapped[x])

#define IS_USER_MCODE(bp, sp, mgroup) ((M_REMAPPABLE((bp)->m_modes[mgroup])) && (((bp)->m_modes[mgroup]) > -1) && ((sp)->m_remapped[(bp)->m_modes[mgroup]]))

    bool remap_in_progress(const char* code);
    int convert_remapped_code(block_pointer block, setup_pointer settings, int phase, char letter, int number = -1);

#define OWORD_MODULE "oword"
#define REMAP_MODULE "remap"
#define NAMEDPARAMS_MODULE "namedparams"
    // describes intented use, and hence parameter and return value
    // interpretation
    FILE* find_ngc_file(setup_pointer settings, const char* basename, char* foundhere = NULL);

    const char* getSavedError();
    // set error message text without going through printf format interpretation
    int setSavedError(const char* msg);

    int unwind_call(int status, const char* file, int line, const char* function);

    int convert_straight_indexer(int anum, int jnum, block* blk, setup* settings);
    int issue_straight_index(int anum, int jnum, double end, int lineno, setup* settings);

    void doLog(unsigned int flags, const char* file, int line, const char* fmt, ...) __attribute__((format(printf, 5, 6)));

    const char* interp_status(int status);

    int initCommWithCamera(const char* addr, int port, const VsnComm* vsnCommCfg);
    void init_speed_override_para();
    void init_set_planner_type();
    int get_thread_type();
    int set_thread_id(int id);
    int set_thread_tid(int id);
    int initOffsetMap(std::string filename);
    int updateSteppingState(int val);
    int reload_zucsettings() override;

    FILE* log_file;

    /*2d vision */
    int cam_sock;
    std::vector<int> sock_list;
    char cam_recv_buf[LINELEN];
    bool parsing_flag;
    bool flag_vision_base;
    ZucPose pos_vision_base;
    VsnComm vsn_comm_cfg;

    /* Internal arrays */
    static const int _gees[];
    static const int _ems[];
    static const int _required_parameters[];
    static const int _readonly_parameters[];
    static const int _n_readonly_parameters;
    read_function_pointer _readers[256];
    static const read_function_pointer default_readers[256];

    setup _setup;

    std::vector<std::pair<int, std::string>> m_owordIdMap;  // the stack is defined to match the "end" statement

    enum
    {
        AXIS_MASK_X = 1,
        AXIS_MASK_Y = 2,
        AXIS_MASK_Z = 4,
        AXIS_MASK_A = 8,
        AXIS_MASK_B = 16,
        AXIS_MASK_C = 32,
        AXIS_MASK_U = 64,
        AXIS_MASK_V = 128,
        AXIS_MASK_W = 256,
    };

    /*timeout control*/
    long long int start_time;

    /*flag to synchronize execution and parsing for certain commands*/
    int interpSynchState;

    int MDImode;

    int progStartLine;
    bool beforeProgStartLine;
    NML* zucErrBuffer;
    Redis _redis;
    int tid = 1;  // sub thread id

protected:
    int m_threadId = 0;  // to indicate if it's a sub-thread (sub-thread > 0)
    SpeedOverrideInfo speed_info_movl, speed_info_movj;
    int set_planner_type = -1;
    /*flag to set endforcecondition flag*/
    int endForceCondFlag;
    int is_mutex = 0;

    bool threadMutexState();
    bool m_multi_thread_flag;
    int m_isSteppingMode = 0;
    int m_steppingWait = 0;
};

class MultiThreadInterp : public Interp
{
public:
    MultiThreadInterp(int threadId);
    multi_thread_setup _setup;
};

#endif
